import { useState, useRef, useEffect, useCallback, useMemo } from 'react'
import styled from 'styled-components'

// https://developer.mozilla.org/en-US/docs/Web/API/Canvas_API/Manipulating_video_using_canvas

/**
  
  ref.current.getBoundingClientRect()
  canvasContext.drawImage
  canvasContext.getImageData
  canvasContext.putImage

  imageData format: rgba

 */
const Wrapper = styled.div`
  min-height: 90vh;
  width: 100%;
  display: grid;
  place-items: center;
  
  & div.container {
    display: inline-block;
  }
  & canvas#c2 {
    background-image: ${"url('https://images.unsplash.com/photo-1655265171060-21004d02ae3b?ixlib=rb-4.0.3&ixid=MnwxMjA3fDB8MHx0b3BpYy1mZWVkfDEwfFJfRnluLUd3dGx3fHxlbnwwfHx8fA%3D%3D&auto=format&fit=crop&w=500&q=60')"};
    background-size:     cover;                      /* <------ */
    background-repeat:   no-repeat;
    background-position: center center;
  }
`

export default function Demo() {
  const refVideo   = useRef<any>(null)
  const [size, setSize] = useState<{width: number; height: number}>({width: 0, height: 0})
  const refCanvas1 = useRef<any>(null)
  const refCanvas2 = useRef<any>(null)
  const [context1, setContext1] = useState<any>(null)
  const [context2, setContext2] = useState<any>(null)

  const video: any = useMemo(() => {
    return document.getElementById("video")
  }, [refVideo.current])

  useEffect(() => {
    const ctx1 = refCanvas1.current?.getContext("2d");
    const ctx2 = refCanvas2.current?.getContext("2d");
    if ((!!ctx1) && (!!ctx2)) {
      setContext1(ctx1);
      setContext2(ctx2);
    }
  }, [])

  const onLoad = () => {
    const {width, height} = refVideo.current.getBoundingClientRect()
    if (!!width && !!height) {
      setSize({width, height})
      refCanvas1.current.width  = width;
      refCanvas1.current.height = height;
      refCanvas2.current.width  = refCanvas1.current.width;
      refCanvas2.current.height = refCanvas1.current.height;
    }
  }

  const updateFrame = useCallback(() => {
    context1.drawImage(video, 0, 0, size.width, size.height);
    const frame = context1.getImageData(0, 0, size.width, size.height);
    const l = frame.data.length;
    for (let i = 0; i < l; i+=4) {
      const r = frame.data[i + 0];
      const g = frame.data[i + 1];
      const b = frame.data[i + 2];
      if (g > 100 && r > 100 && b < 43) {
        frame.data[i + 3] = 0;
      }
    }
    context2.putImageData(frame, 0, 0);
  }, [size, video, context1, context2])

  const timerCB = useCallback(() => {
    if (!video.paused && !video.ended) {
      updateFrame()
      setTimeout(timerCB, 20)
    }
  }, [updateFrame, video])
  const onPlay = () => {
    timerCB()
  }

  return (
    <Wrapper>
      <h1>Chroma Keying</h1>
      <video id='video' ref={refVideo} src="/video.mp4" controls onLoadedMetadata={onLoad} onPlay={onPlay} />
      <canvas id="c1" ref={refCanvas1} width="10" height="6">!!! This browser doesn't support canvas !!!</canvas>
      <canvas id="c2" ref={refCanvas2} width="10" height="6">!!! This browser doesn't support canvas !!!</canvas>
    </Wrapper>
  )
}
